#include "IdNode.h"

#include <deque>

namespace jcrada {

    IdNode::IdNode(int arity) : Node(arity),
    _id(0) {

    }

    IdNode::IdNode(int arity, int id) : Node(arity),
    _id(id) {

    }

    IdNode::~IdNode() {

    }

    IdNode* IdNode::findNodeByIdUsingBFS(int id) {
        if (getId() == id) {
            return this;
        }
        //BFS
        const IdNode* n = NULL;
        IdNode* child = NULL;
        std::deque<IdNode*> deque;
        deque.push_back(this);
        while (deque.size() > 0) {
            n = deque.front();
            for (int i = 0; i < n->getArity(); ++i) {
                child = dynamic_cast<IdNode*> (n->getChild(i));
                if (child) {
                    if (child->getId() == id) {
                        return child;
                    }
                    deque.push_back(child);
                }
            }
            deque.pop_front();
        }
        return NULL;
    }

    IdNode* IdNode::clone() const {
        IdNode* result = new IdNode(getArity());
        result->setId(getId());
        Node* child = NULL;
        for (int i = 0; i < getArity(); ++i) {
            if (getChild(i) != NULL) {
                child = getChild(i)->clone();
                child->moveTo(result, i);
            }
        }
        return result;
    }

    std::string IdNode::toString() const {
        return TO_STRING(getId());
    }

    std::string IdNode::toStringDown(int level) const {
        std::string result;
        for (int i = 0; i < getArity(); ++i) {
            if (getChild(i) != NULL) {
                result += getChild(i)->toStringDown(level + 1) + " ";
            }
        }
        if (getNumberOfChildren() > 0) {
            result += "-";
        }
        result += toString();
        if (getNumberOfChildren() > 0) {
            result += "[" + TO_STRING(level) + "]";
        }
        return result;
    }

    void IdNode::toXml(QDomDocument& xml, QDomElement* parent) const {
        QDomElement node = xml.createElement("IdNode");
        node.setAttribute("arity", getArity());
        node.setAttribute("id",getId());
        Node* child = NULL;
        for (int i = 0; i < getArity(); ++i) {
            child = getChild(i);
            if (child) {
                child->toXml(xml, &node);
            }
        }
        if (parent) {
            parent->appendChild(node);
        } else {
            xml.appendChild(node);
        }
    }

    std::string IdNode::toXml() const{
        QDomDocument doc;
        toXml(doc);
        return doc.toString().toStdString();
    }

    int IdNode::main(int argc, char** argv) {
        int id = 0;
        IdNode root(3, id++);

        IdNode l1a(3, id++);
        IdNode l2aa(0, id++);
        IdNode l2ab(0, id++);
        IdNode l2ac(0, id++);

        IdNode l1b(3, id++);
        IdNode l2ba(0, id++);
        IdNode l2bb(0, id++);
        IdNode l2bc(0, id++);

        IdNode l1c(3, id++);
        IdNode l2ca(0, id++);
        IdNode l2cb(0, id++);
        IdNode l2cc(0, id++);

        l1a.moveTo(&root, 0);
        l1b.moveTo(&root, 1);
        l1c.moveTo(&root, 2);

        l2aa.moveTo(&l1a, 0);
        l2ab.moveTo(&l1a, 1);
        l2ac.moveTo(&l1a, 2);

        l2ba.moveTo(&l1b, 0);
        l2bb.moveTo(&l1b, 1);
        l2bc.moveTo(&l1b, 2);

        l2ca.moveTo(&l1c, 0);
        l2cb.moveTo(&l1c, 1);
        l2cc.moveTo(&l1c, 2);

        std::cout << "root" << std::endl;
        std::cout << "down" << std::endl;
        std::cout << root.toStringDown() << std::endl;
        std::cout << "up" << std::endl;
        std::cout << root.toStringUp() << std::endl;
        return 0;
    }
}
